package com.lxl.filter;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.lxl.configuration.RedisUtil;
import com.wust.Hisportal.etl.interfaceAuth.vo.InterfaceAuth;
import com.lxl.jpa.InterfaceAuthJPA;
import com.lxl.pojo.BaseIp;
import com.lxl.pojo.BaseResponse;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.RedisConnectionFailureException;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

public class AuthFilter extends ZuulFilter {
    private static Logger logger = LoggerFactory.getLogger(AuthFilter.class);

    @Autowired
    private InterfaceAuthJPA interfaceAuthJPA;
    @Autowired
    private RedisUtil redisUtil;

    @Override
    public String filterType() {
        return "route";
    }

    @Override
    public int filterOrder() {
        return 0;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() throws ZuulException {
        BaseResponse baseResponse = new BaseResponse();
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        String servletPath = StringUtils.substring(request.getServletPath(), 0, 3);
        String taskType = getTaskType(servletPath);
        String taskName = null;
        if (StringUtils.equals(taskType, "external")) {
            //如果是外部http接口，则去掉请求中的/wb进行比对
            //taskName = StringUtils.substring(request.getServletPath(), 3);
            taskName = StringUtils.substring(request.getServletPath(),
                    StringUtils.lastIndexOf(request.getServletPath(), "/") + 1);
        } else {
            taskName = request.getParameter(getTaskName(servletPath));
        }
        String ip = getIpAddress(request);

        try {
            //从Redis中获取权限数据
            String authKey = new StringBuilder("auth").append("_").append(taskType).append("_").append(taskName).toString();
            Object authObject = redisUtil.get(authKey);

            //List<InterfaceAuthEntity> entities = interfaceAuthJPA.selectInterfaceAuthFromTypeAndName(taskType,taskName);

            if (ObjectUtil.isNotNull(authObject)) {
                List<InterfaceAuth> authList = (List<InterfaceAuth>) authObject;
                for (InterfaceAuth entity : authList) {
                    if (checkForInclusion(ip, entity.getAuthorizedIP())) {
                        //检查通过
                        ctx.setSendZuulResponse(true);
                        return null;
                    }
                }
            }
        } catch (RedisConnectionFailureException e) {
            e.printStackTrace();
            //如果Redis连接不上，则默认检查通过
            ctx.setSendZuulResponse(true);
            return null;
        } catch (Exception e) {
            e.printStackTrace();
        }

        baseResponse.fail();
        ctx.setResponseStatusCode(404);
        ctx.setResponseBody(baseResponse.toString());
        ctx.setSendZuulResponse(false);
        return null;
    }

    private static String getTaskType(String path) {
        switch (path) {
            case "/st":
                return "shortTrans";
            case "/sj":
                return "shortJob";
            case "/lt":
                return "longTrans";
            case "/lj":
                return "longJob";
            case "/wb":
                return "external";
            default:
                return null;
        }
    }

    private static String getTaskName(String param) {
        switch (param) {
            case "/st":
            case "/lt":
                return "trans";
            case "/sj":
            case "/lj":
                return "job";
            default:
                return null;
        }
    }

    private final static String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");

        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("Proxy-Client-IP");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("WL-Proxy-Client-IP");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_CLIENT_IP");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_X_FORWARDED_FOR");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getRemoteAddr();
            }
        } else if (ip.length() > 15) {
            String[] ips = ip.split(",");
            for (int index = 0; index < ips.length; index++) {
                String strIp = (String) ips[index];
                if (!("unknown".equalsIgnoreCase(strIp))) {
                    ip = strIp;
                    break;
                }
            }
        }
        return ip.equals("0:0:0:0:0:0:0:1") ? "127.0.0.1" : ip;
    }

    public static boolean checkForInclusion(String reqIpStr, String scopeStr) {
        BaseIp reqIp = new BaseIp(reqIpStr);
        String[] scopeStrList = scopeStr.split("-");
        BaseIp start = new BaseIp(scopeStrList[0]);
        if (scopeStrList.length > 1) {
            BaseIp end = new BaseIp(scopeStrList[1]);
            if (reqIp.getLong() >= start.getLong() && reqIp.getLong() <= end.getLong()) {
                return true;
            } else {
                return false;
            }
        } else {
            if (reqIp.getLong() >= start.getLong()) {
                return true;
            } else {
                return false;
            }
        }

    }
}
